package compiler;

import compiler.CompilerException;
import edu.towson.cosc.cosc445.interfaces.SyntaxAnalyzerInterface;

import java.io.*;

public class SyntaxAnalyzer implements SyntaxAnalyzerInterface {
	
	/** Lexical Analyzer to be used in the Syntax Analysis **/
	LexicalAnalyzer l;
	
	/** parameterless constructor **/
	public SyntaxAnalyzer(){
		l = new LexicalAnalyzer();
	}
	
	/** 
	 * standard constructor for file intake
	 * @param f file to be examined for compilation
	 */
	public SyntaxAnalyzer(File f){
		l = new LexicalAnalyzer(f);
	}
	
	//TODO: implementation of ENBF rule for text that isnt tags
	//ie while !isSpace()
	public void text() throws CompilerException{
		
	}

	/**
	 * This method implements the BNF grammar rule for the document annotation.
	 * @throws CompilerException
	 */
	public void lolcode() throws CompilerException{
		l.getNextToken();
		if(!l.nextToken.equals("#HAI")) throw new CompilerException("Syntax Error at token " + l.currentPosition + " " + "\"" + l.nextToken + "\"" + ": The file does not begin with \"#HAI\"");
		
		l.getNextToken();
		if(l.nextToken.equals("#OBTW"))comment();
		
		define();
		
		l.getNextToken();
		if(l.nextToken.equals("#MAEK HEAD"))head();
		
		l.getNextToken();
		body();
		
		l.getNextToken();
		if(!l.nextToken.equals("#KTHXBYE")) throw new CompilerException("Syntax Error at token " + l.currentPosition + " " + "\"" + l.nextToken + "\"" + ": The file does not end with \"#KTHXBYE\"");
	}

	/**
	 * This method implements the BNF grammar rule for the head annotation.
	 * @throws CompilerException
	 */
	public void comment() throws CompilerException{
		text();
		
		l.getNextToken();
		if(!l.nextToken.equals("#TLDR")) throw new CompilerException("Syntax Error at token " + l.currentPosition + " " + "\"" + l.nextToken + "\"" + ": The comment block does not end with \"#TLDR\"");
	}

	/**
	 * This method implements the BNF grammar rule for the head annotation.
	 * @throws CompilerException
	 */
	public void head() throws CompilerException{
		l.getNextToken();
		title();
		
		l.getNextToken();
		if(!l.nextToken.equals("#OIC")) throw new CompilerException("Syntax Error at token " + l.currentPosition + " " + "\"" + l.nextToken + "\"" + ": The head block does not end with \"#OIC\"");
	}

	/**
	 * This method implements the BNF grammar rule for the title annotation.
	 * @throws CompilerException

	 */
	public void title() throws CompilerException{
		if(l.nextToken.equals("#GIMMEH TITLE")){
			text();
			l.getNextToken();
			if(!l.nextToken.equals("#MKAY")) throw new CompilerException("Syntax Error at token " + l.currentPosition + " " + "\"" + l.nextToken + "\"" + ": The title block does not end with \"#MKAY\"");
		}
		else return;
	}
	
	/**
	 * This method implements the BNF grammar rule for the body annotation.
	 * @throws CompilerException
	 */
	public void body() throws CompilerException{
		if(l.nextToken.equals("#OBTW")){
			comment();

			l.getNextToken();
			body();
		}
		else if(l.nextToken.equals("#VISIBLE") || (!l.nextToken.substring(0,1).equals("#")) || l.nextToken.equals("#GIMMEH NEWLINE") || l.nextToken.equals("#GIMMEH SOUNDZ") || l.nextToken.equals("#GIMMEH VIDZ")){
			innerText();

			l.getNextToken();
			body();
		}
		else if(l.nextToken.equals("#MAEK PARAGRAF")){
			paragraph();

			l.getNextToken();
			body();
		}
		else if(l.nextToken.equals("#GIMMEH BOLD")){
			bold();

			l.getNextToken();
			body();
		}
		else if(l.nextToken.equals("#GIMMEH ITALICS")){
			italics();

			l.getNextToken();
			body();
		}
		else if(l.nextToken.equals("#MAEK LIST")){
			list();
			
			l.getNextToken();
			body();
		}
	}

	/**
	 * This method implements the BNF grammar rule for the paragraph annotation.
	 * @throws CompilerException
	 */
	public void paragraph() throws CompilerException{
		l.getNextToken();
		define();
		
		l.getNextToken();
		innerParagraph();
		
		l.getNextToken();
		if(!l.nextToken.equals("#OIC")) throw new CompilerException("Syntax Error at token " + l.currentPosition + " " + "\"" + l.nextToken + "\"" + ": The paragraph block does not end with \"#OIC\"");
	}
	
	public void innerParagraph() throws CompilerException{
		if(l.nextToken.equals("#VISIBLE") || (!l.nextToken.substring(0,1).equals("#")) || l.nextToken.equals("#GIMMEH NEWLINE") || l.nextToken.equals("#GIMMEH SOUNDZ") || l.nextToken.equals("#GIMMEH VIDZ")){
			innerText();

			l.getNextToken();
			innerParagraph();
		}
		else if(l.nextToken.equals("#GIMMEH BOLD")){
			bold();

			l.getNextToken();
			innerParagraph();
		}
		else if(l.nextToken.equals("#GIMMEH ITALICS")){
			italics();

			l.getNextToken();
			innerParagraph();
		}
		else if(l.nextToken.equals("#MAEK LIST")){
			list();
			
			l.getNextToken();
			innerParagraph();
		}
		else if(l.nextToken.equals("#GIMMEH NEWLINE")){
			newLine();

			l.getNextToken();
			innerParagraph();
		}
	}
	
	/**
	 * This method implements the BNF grammar rule for the newline annotation.
	 * @throws CompilerException
	 */
	public void newLine() throws CompilerException{
		if(l.nextToken.equals("#GIMMEH NEWLINE")){
			l.getNextToken();
		}
		if(l.nextToken.equals("#GIMMEH NEWLINE")) newLine();
	}
	
	public void innerText() throws CompilerException{
		if(l.nextToken.equals("#VISIBLE")){
			use();
		}
		else if(l.nextToken.equals("#GIMMEH NEWLINE")){
			newLine();
		}
		else if(l.nextToken.equals("#GIMMEH SOUNDZ")){
			audio();
		}
		else if(l.nextToken.equals("#GIMMEH VIDZ")){
			video();
		}
		else if(l.nextToken.length() == 0);
		else if(!l.nextToken.substring(0,1).equals("#")){
			text();
		}
	}
	
	/**
	 * This method implements the BNF grammar rule for the bold annotation.
	 * @throws CompilerException
	 */
	public void bold() throws CompilerException{
		if(l.nextToken.equals("#GIMMEH BOLD")){
			l.getNextToken();
			if(l.nextToken.equals("#VISIBLE")) use();
			
			l.getNextToken();
			innerText();
			
			l.getNextToken();
			if(!l.nextToken.equals("#MKAY"))throw new CompilerException("Syntax error at token " + l.currentPosition + " " + "\"" + l.nextToken + "\"" + ": no end tag found for bold");
		}
	}

	/**
	 * This method implements the BNF grammar rule for the italics annotation.
	 * @throws CompilerException
	 */
	public void italics() throws CompilerException{
		if(l.nextToken.equals("#GIMMEH ITALICS")){
			l.getNextToken();
			if(l.nextToken.equals("#VISIBLE")) use();
			
			l.getNextToken();
			innerText();
			
			l.getNextToken();
			if(!l.nextToken.equals("#MKAY")) throw new CompilerException("Syntax error at token " + l.currentPosition + " " + "\"" + l.nextToken + "\"" + ": no end tag found for italics");
		}
	}

	/**
	 * This method implements the BNF grammar rule for the list annotation.
	 * @throws CompilerException
	 */
	public void list() throws CompilerException{
		if(l.nextToken.equals("#MAEK LIST")){
			l.getNextToken();
			if(!l.nextToken.equals("#GIMMEH ITEM")) throw new CompilerException("Syntax error at token " + l.currentPosition + " " + "\"" + l.nextToken + "\"" + ": no start tag found for first list item, list must have at least 1 item");
			
			l.getNextToken();
			innerList();
			
			l.getNextToken();
			if(!l.nextToken.equals("#MKAY"))throw new CompilerException("Syntax error at token " + l.currentPosition + " " + "\"" + l.nextToken + "\"" + ": no end tag found for first item, list must have at least 1 item");
			
			l.getNextToken();
			item();
			
			l.getNextToken();
			if(!l.nextToken.equals("#MKAY")) throw new CompilerException("Syntax error at token " + l.currentPosition + " " + "\"" + l.nextToken + "\"" + ": no end tag found for list");
		}
	}

	/**
	 * This method implements the BNF grammar rule for the item annotation.
	 * @throws CompilerException
	 */
	public void item() throws CompilerException{
		if(l.nextToken.equals("#GIMMEH ITEM")){
			l.getNextToken();
			innerList();
			
			l.getNextToken();
			if(!l.nextToken.equals("#MKAY"))throw new CompilerException("Syntax error at token " + l.currentPosition + " " + "\"" + l.nextToken + "\"" + ": expected item end tag");
			else{
				l.getNextToken();
				item();
			}
		}
	}
	
	/**
	 * This method implements the BNF grammar rule for the inner-list annotation.
	 * @throws CompilerException
	 */
	public void innerList() throws CompilerException{
		if(l.nextToken.equals("#GIMMEH BOLD")){
			bold();
			
			l.getNextToken();
			innerList();
		}
		else if(l.nextToken.equals("#GIMMEH ITALICS")){
			italics();
			
			l.getNextToken();
			innerList();
		}
		else if(l.nextToken.equals("#MAEK LIST")){
			list();
			
			l.getNextToken();
			innerList();
		}
		else if(l.nextToken.equals("#VISIBLE") || (!l.nextToken.substring(0,1).equals("#")) || l.nextToken.equals("#GIMMEH NEWLINE") || l.nextToken.equals("#GIMMEH SOUNDZ") || l.nextToken.equals("#GIMMEH VIDZ")){
			innerText();
			
			l.getNextToken();
			innerList();
		}
	}

	/**
	 * This method implements the BNF grammar rule for the audio annotation.
	 * @throws CompilerException
	 */
	public void audio() throws CompilerException{
		if(l.nextToken.equals("#GIMMEH SOUNDZ")){
			l.getNextToken();
			text();
			
			l.getNextToken();
			if(!l.nextToken.equals("#MKAY")) throw new CompilerException("Syntax error at token " + l.currentPosition + " " + "\"" + l.nextToken + "\"" + ": expected audio end tag");
		}
	}

	/**
	 * This method implements the BNF grammar rule for the video annotation.
	 * @throws CompilerException
	 */
	public void video() throws CompilerException{
		if(l.nextToken.equals("#GIMMEH VIDZ")){
			l.getNextToken();
			text();
			
			l.getNextToken();
			if(!l.nextToken.equals("#MKAY")) throw new CompilerException("Syntax error at token " + l.currentPosition + " " + "\"" + l.nextToken + "\"" + ": expected video end tag");
		}
	}

	/**
	 * This method implements the BNF grammar rule for the define annotation.
	 * @throws CompilerException
	 */
	public void define() throws CompilerException{
		if(l.nextToken.equals("#I HAS A")){
			l.getNextToken();
			text();
			
			l.getNextToken();
			if(!l.nextToken.equals("#ITZ")) throw new CompilerException("Syntax error at token " + l.currentPosition + " " + "\"" + l.nextToken + "\"" + ": expected a value declaration for variable");
			else{
				l.getNextToken();
				text();
				if(!l.nextToken.equals("#ITZ")) throw new CompilerException("Syntax error at token " + l.currentPosition + " " + "\"" + l.nextToken + "\"" + ": expected an end tag for variable definition");
				else{
					l.getNextToken();
					define();
				}
			}
		}
	}

	/**
	 * This method implements the BNF grammar rule for the use annotation.
	 * @throws CompilerException
	 */
	public void use() throws CompilerException{
		if(l.nextToken.equals("#VISIBLE")){
			l.getNextToken();
			text();
			
			l.getNextToken();
			if(!l.nextToken.equals("#MKAY")) throw new CompilerException("Syntax error at token " + l.currentPosition + " " + "\"" + l.nextToken + "\"" + ": expected an end tag for variable usage");
		}
	}

}
